# coding =  utf-8
#qq邮箱自动登录-----滑动验证码

import  os
import random
import sys
import time

import cv2
import numpy as np
import  requests
from PIL import Image as Im
from selenium import webdriver
from selenium.webdriver import ActionChains

class QQ_Email(object):
    def __init__(self):
        self.root = sys.path[0]+"/pic/"
        self.driver =  webdriver.Firefox(executable_path="C:\\Users\\Administrator\\Desktop\\package\\python\\geckodriver.exe")
    def Email(self,user,pwd):
        start_url = "https://mail.qq.com"
        time.sleep(2)
        self.driver.get(start_url)
        time.sleep(2)

        #切换frame,login_frame是该登录窗口iframe的id
        self.driver.switch_to.frame("login_frame")

        try:
            #点击选择账号密码登录
            self.driver.find_element_by_id("switcher_plogin").click()
        except Exception as e:
            print(e)

        time.sleep(1)
        #输入账号 将user输入id是u的输入框
        self.driver.find_element_by_id("u").clear()
        self.driver.find_element_by_id("u").send_keys(user)
        time.sleep(1)
        #输入密码   将pwd填入id是p的输入框
        self.driver.find_element_by_id("p").clear()
        self.driver.find_element_by_id("p").send_keys(pwd)
        time.sleep(1)

        check_before_url  = self.driver.current_url
        #点击登录 登录按钮的id是login_button
        self.driver.find_element_by_id("login_button").click()
        time.sleep(2)

        if "安全验证" in self.driver.page_source:
            print("有验证码")
            os.system("pause")

            self.Verification_code()
        else:
            print("无验证码，登录成功！！！")

    def pic_download(self,url,pic_type):
        url = url
        path = self.root+pic_type+".png"
        try:
            if not os.path_exists(self.root):
                os.makedird(self.root)
            if os.path.exists(path):
                os.remove(path)
            r = requests.get(url)
            r.raise_for_status()
            #使用with语句可以不用自己手动关闭已经打开的文件
            with open(path,"wb") as f:
                f.write(r.content)

            print("%s 图片下载完成" %  pic_type)
            return f.name
        except Exception as e:
            print("获取失败！"+str(e))
            self.pic_download(url,pic_type)

    def get_distance(self,small_url,big_url):
        otemp = self.pic_download(small_url,'small')
        time.sleep(2)
        oblk = self.pic_download(big_url,'big')

        #计算拼图还原距离
        target = cv2.imread(otemp, 0)
        template = cv2.imread(oblk, 0)
        w, h = target.shape[::-1]
        temp = self.root + 'temp.jpg'
        targ = self.root + 'targ.jpg'
        cv2.imwrite(temp, template)
        cv2.imwrite(targ, target)
        target = cv2.imread(targ)
        target = cv2.cvtColor(target, cv2.COLOR_BGR2GRAY)
        target = abs(255 - target)
        cv2.imwrite(targ, target)
        target = cv2.imread(targ)
        template = cv2.imread(temp)
        result = cv2.matchTemplate(target, template, cv2.TM_CCOEFF_NORMED)
        x, y = np.unravel_index(result.argmax(), result.shape)
        # 缺口位置
        print((y, x, y + w, x + h))

        # 调用PIL Image 做测试
        image = Im.open(oblk)

        xy = (y + 20, x + 20, y + w - 20, x + h - 20)
        # 切割
        imagecrop = image.crop(xy)
        # 保存切割的缺口
        imagecrop.save(sys.path[0] + "/pic/new_image.jpg")
        return y

    def Verification_code(self):
        #切换最初的frame中
        self.driver.switch_to.default_content()

        #切换frame
        self.driver.switch_to.frame("login_frame")

        #切换带有刷新按钮的frame
        self.driver.switch_to.frma(self.driver.find_element_by_xpath('//*[@id="newVcodeIframe"]/iframe'))

        #点击刷新id为e_reload
        self.driver.find_enement_by("e_reload").click()

        #获取图片连接
        big_url = self.driver.find_element_by_id('slideBg').get_attribute("src")
        small_url = self.driver.find_element_by_id("slideBlock").get_attribute("src")

        y = self.get_distance(small_url,big_url)

        slide_before_url = self.driver.current_url

        #获取蓝色按钮对象
        element = self.driver.find_element_by_id('tcaptcha_drag_button')

        #计算distance(记住要=用浮点数，不然计算后会取整)
        distance = y*(280.0/680.0)-31
        print('distance:',distance)
        #模拟人拖动按钮
        has_gone_dist = 0
        remaining_dist = distance
        #按下鼠标左键
        ActionChains(self.driver).click_and_hold(element).perform()
        time.sleep(0.5)
        while remaining_dist > 0:
            ratio = remaining_dist / distance
            if ratio < 0.2:
                #开始阶段移动较慢
                span = random.randint(5,8)
            elif ratio > 0.8:
                #结束段移动较慢
                span  = random.randint(5,8)
            else:
                #中间段移动较快
                span = random.randint(10,16)
                ActionChains(self.driver).move_by_offset(span,random.randint(-5,5)).perform()
                remaining_dist -= span
                has_gone_dist += span
                time.sleep(random.randint(5,20)/100)

        ActionChains(self.driver).move_by_offset(remaining_dist,random.randint(-5,5)).perform()
        ActionChains(self.driver).release(on_emelent=element).perform()

        #获取当前的网页地址
        slide_after_url = self.driver.current_url

        #frame切回到上一层
        self.driver.switch_to.parent_frame()

        #判断拖动后和拖动前的地址是否有变化，如果变了则说明登录成功（失败则停留在该页面）
        if slide_before_url == slide_after_url:
            try:
                #切换到最初的frame框架中
                self.driver.switch_to.default_content()
                #将farme切换到login_frame
                self.driver.switch_to.frame('login_frame')
                self.driver.switch_to.frame('tcaptcha_iframe')
                print(self.driver.find_element_by_id('guideText').text)
                print('滑动失败')
                self.Verification_code()  #若滑动失败，则重复此动作
            except:
                print('账号有误！')
        else:
            print("登录成功")

#main方法
if __name__ == "__main__":
    run = QQ_Email()
    run.Email("845064749","weinichikuang19881020")